package com.yanfan.zutai.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.yanfan.common.core.redis.RedisCache;
import com.yanfan.common.core.text.Convert;

import com.yanfan.common.utils.DateUtils;
import com.yanfan.mqtt.manager.MqttRemoteManager;
import com.yanfan.mqtt.model.PushMessageBo;
import com.yanfan.zutai.config.TaosConnectTool;
import com.yanfan.zutai.domain.BDeviceRealData;
import com.yanfan.zutai.domain.vo.*;
import com.yanfan.zutai.mapper.BDeviceRealDataMapper;
import com.yanfan.zutai.service.IBDeviceRealDataService;
import com.yanfan.zutai.util.DateUtilLocal;
import com.yanfan.zutai.util.Detect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 设备实时数据Service业务层处理
 *
 * @author ruoyi
 * @date 2022-05-27
 */
@Service
public class BDeviceRealDataServiceImpl implements IBDeviceRealDataService {
    @Autowired
    private BDeviceRealDataMapper bDeviceRealDataMapper;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Value("${spring.datasource.druid.tdengine-server.enabled}")
    private Boolean enabled;
    @Autowired
    private RedisCache redisCache;
    @Resource
    private MqttRemoteManager remoteManager;

    /**
     * 查询设备实时数据
     *
     * @param id 设备实时数据ID
     * @return 设备实时数据
     */
    @Override
    public BDeviceRealData selectBDeviceRealDataById(Long id) {
        return bDeviceRealDataMapper.selectBDeviceRealDataById(id);
    }

    /**
     * 查询设备实时数据列表
     *
     * @param bDeviceRealData 设备实时数据
     * @return 设备实时数据
     */
    @Override
    public List<BDeviceRealData> selectBDeviceRealDataList(BDeviceRealData bDeviceRealData) {
        return bDeviceRealDataMapper.selectBDeviceRealDataList(bDeviceRealData);
    }

    /**
     * 新增设备实时数据
     *
     * @param bDeviceRealData 设备实时数据
     * @return 结果
     */
    @Override
    public Integer insertBDeviceRealData(BDeviceRealData bDeviceRealData) {
        bDeviceRealData.setParamValue("0");
        bDeviceRealData.setCreateTime(DateUtils.getNowDate());
        String guid = UUID.randomUUID().toString();
        bDeviceRealData.setGuid(guid);
        if (Detect.isEmpty(bDeviceRealData.getParamField())) {
            Integer maxSortId = getMaxSortId(bDeviceRealData.getDeviceImei());
            bDeviceRealData.setParamField("A" + maxSortId);
            bDeviceRealData.setSort(maxSortId);
        }
        Snowflake snowflake = IdUtil.getSnowflake(6, 2);
        long id = snowflake.nextId();
        bDeviceRealData.setId(id);
        bDeviceRealDataMapper.insertBDeviceRealData(bDeviceRealData);
        return 200;
    }

    /**
     * 修改设备实时数据
     *
     * @param bDeviceRealData 设备实时数据
     * @return 结果
     */
    @Override
    public Integer updateBDeviceRealData(BDeviceRealData bDeviceRealData) {
        bDeviceRealData.setUpdateTime(DateUtils.getNowDate());
        if (Detect.isEmpty(bDeviceRealData.getParamField())) {
            Integer maxSortId = getMaxSortId(bDeviceRealData.getDeviceImei());
            bDeviceRealData.setParamField("A" + maxSortId);
            bDeviceRealData.setSort(maxSortId);
        }
        bDeviceRealDataMapper.updateBDeviceRealData(bDeviceRealData);
        return 200;
    }

    /**
     * 批量删除设备实时数据
     *
     * @param ids 需要删除的设备实时数据ID
     * @return 结果
     */
    @Override
    public int deleteBDeviceRealDataByIds(Long[] ids) {
        List<BDeviceRealData> list = new ArrayList<>();
        for (int i = 0; i < ids.length; i++) {
            BDeviceRealData bDeviceRealData = bDeviceRealDataMapper.selectBDeviceRealDataById(ids[i]);
            list.add(bDeviceRealData);
        }
        bDeviceRealDataMapper.deleteBDeviceRealDataByIds(ids);
        for (int i = 0; i < list.size(); i++) {
            BDeviceRealData bDeviceRealData = list.get(i);
            jdbcTemplate.update("delete from b_device_warn_config where real_data_guid=?", bDeviceRealData.getDeviceImei() + "-" + bDeviceRealData.getParamField());
            jdbcTemplate.update("delete from b_device_parameter where real_data_guid=?", bDeviceRealData.getDeviceImei() + "-" + bDeviceRealData.getParamField());
        }
        return 200;
    }

    /**
     * 删除设备实时数据信息
     *
     * @param id 设备实时数据ID
     * @return 结果
     */
    @Override
    public int deleteBDeviceRealDataById(Long id) {
        return bDeviceRealDataMapper.deleteBDeviceRealDataById(id);
    }

    @Override
    public String importData(List<BDeviceRealData> list) {
        for (int i = 0; i < list.size(); i++) {
            BDeviceRealData bDeviceRealData = list.get(i);
            String guid = UUID.randomUUID().toString();
            bDeviceRealData.setGuid(guid);
            if (Detect.isEmpty(bDeviceRealData.getParamField())) {
                Integer maxSortId = getMaxSortId(bDeviceRealData.getDeviceImei());
                bDeviceRealData.setParamField("A" + maxSortId);
                bDeviceRealData.setSort(maxSortId);
            }
            Snowflake snowflake = IdUtil.getSnowflake(6, 2);
            long id = snowflake.nextId();
            bDeviceRealData.setId(id);
            bDeviceRealDataMapper.insertBDeviceRealData(bDeviceRealData);
            redisCache.setCacheObject("RealData-" + bDeviceRealData.getDeviceImei() + "-" + bDeviceRealData.getParamField(), bDeviceRealData);
        }
        return "导入成功" + list.size() + "条";
    }

    @Override
    public Integer getMaxSortId(String deviceImei) {
        String sql = "SELECT max(sort) as sortId FROM b_device_real_data where device_imei=?";
        BeanPropertyRowMapper<BDeviceSortId> beanPropertyRowMapper = new BeanPropertyRowMapper<>(BDeviceSortId.class);
        try {
            BDeviceSortId bDeviceSortId = jdbcTemplate.queryForObject(sql, beanPropertyRowMapper, deviceImei);
            return bDeviceSortId.getSortId() + 1;
        } catch (Exception e) {
            return 1;
        }
    }

    @Override
    public List<BDeviceRealDataLineVo> getVariableLine(BDeviceRealDataLineVo bDeviceRealData) {
        BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper<>(BDeviceRealDataLineVo.class);
        List<BDeviceRealDataLineVo> queryList = new ArrayList<>();
        if (enabled) {
            String sql = "SELECT AVG(param_value) as param_value FROM b_device_history_data" + "  WHERE device_imei=? and param_name=? and report_time>=NOW-2h and report_time<=now " + "  INTERVAL(?m) FILL(VALUE, 0.0);";
            queryList = TaosConnectTool
                    .getInstance()
                    .getJdbcTemplate()
                    .query(sql, rowMapper, bDeviceRealData.getDeviceImei(), bDeviceRealData.getParamName(), bDeviceRealData.getMinute());
            String startDate = DateUtilLocal.format(DateUtil.offsetHour(new Date(), -2), DateUtilLocal.TIMESTAMP_PATTERN);
            String endDate = DateUtilLocal.format(new Date(), DateUtilLocal.TIMESTAMP_PATTERN);
            List<String> timeList = DateUtilLocal.getDateListByMinute(startDate, endDate, 1);
            for (int i = 0; i < queryList.size(); i++) {
                BDeviceRealDataLineVo bDeviceRealDataLineVo = queryList.get(i);
                bDeviceRealDataLineVo.setParamTime(timeList.get(i));
            }
        } else {
            String sql = "SELECT param_time, sum(param_value) param_value " + "FROM" + "    (" + "    SELECT param_value,\n" + "        DATE_FORMAT(\n" + "            concat( date( report_time ), ' ', HOUR ( report_Time ), ':', floor( MINUTE ( report_time ) / ? ) * ? ),\n" + "            '%Y-%m-%d %H:%i' " + "        ) AS param_time " + "    FROM b_device_history_data" + "    WHERE device_imei=? and param_name=? ORDER BY report_Time desc LIMIT ?" + "    ) a \n" + "GROUP BY param_time \n" + "ORDER BY param_time asc ;";
            queryList = jdbcTemplate.query(sql, rowMapper, bDeviceRealData.getMinute(), bDeviceRealData.getMinute(), bDeviceRealData.getDeviceImei(), bDeviceRealData.getParamName(), bDeviceRealData.getQueryNum());
        }
        return queryList;
    }

    @Override
    public BDeviceRealDataLinesVo getVariableLines(BDeviceRealDataLinesVo bDeviceRealData) {
        List<String> timeList = new ArrayList<>();
        List<DataLineVo> list = new ArrayList<>();
        BDeviceRealDataLinesVo linesVo = new BDeviceRealDataLinesVo();
        if (enabled) {
            for (int i = 0; i < bDeviceRealData.getParamNameList().size(); i++) {
                DataLineVo dataLineVo = new DataLineVo();
                String paramField = bDeviceRealData.getParamFieldList().get(i);
                String paramName = bDeviceRealData.getParamNameList().get(i);
                String deviceImei = bDeviceRealData.getDeviceImeiList().get(i);
                dataLineVo.setParamName(paramName);
                List<Double> doubleList = new ArrayList<>();
                BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper<>(BDeviceRealDataLineVo.class);
                Long startTime = DateUtilLocal
                        .parseDate(bDeviceRealData.getStartTime(), DateUtilLocal.TIMESTAMP_PATTERN)
                        .getTime();
                Long endTime = DateUtilLocal
                        .parseDate(bDeviceRealData.getEndTime(), DateUtilLocal.TIMESTAMP_PATTERN)
                        .getTime();
                List<BDeviceRealDataLineVo> queryList;
                String sql = "SELECT AVG(param_value) as param_value FROM b_device_history_data" + "  WHERE device_imei=? and param_field=? and report_time>=? and report_time<=? " + "  INTERVAL(?m) FILL(VALUE, 0.0) ;";
                queryList = TaosConnectTool
                        .getInstance()
                        .getJdbcTemplate()
                        .query(sql, rowMapper, deviceImei, paramField, bDeviceRealData.getStartTime(), bDeviceRealData.getEndTime(), bDeviceRealData.getMinute());
                for (int j = 0; j < queryList.size(); j++) {
                    doubleList.add(Convert.toDouble(queryList.get(j).getParamValue()));
                }
                dataLineVo.setData(doubleList);
                list.add(dataLineVo);
            }
            timeList = DateUtilLocal.getDateListByMinute(bDeviceRealData.getStartTime(), bDeviceRealData.getEndTime(), bDeviceRealData.getMinute());
            linesVo.setTimeList(timeList);
            linesVo.setList(list);
        } else {
            for (int i = 0; i < bDeviceRealData.getParamNameList().size(); i++) {
                DataLineVo dataLineVo = new DataLineVo();
                String paramName = bDeviceRealData.getParamNameList().get(i);
                dataLineVo.setParamName(paramName);
                List<Double> doubleList = new ArrayList<>();
                String sql = "SELECT param_time, param_value " + "FROM" + "    (" + "    SELECT param_value,\n" + "        DATE_FORMAT(\n" + "            concat( date( report_time ), ' ', HOUR ( report_Time ), ':', floor( MINUTE ( report_time ) / ? ) * ? ),\n" + "            '%Y-%m-%d %H:%i' " + "        ) AS param_time " + "    FROM b_device_history_data" + "    WHERE device_imei=? and param_name=?  " + "AND date_format(report_Time,'%Y%m%d %H:%M:%S') >= date_format(?,'%Y%m%d %H:%M:%S') " + "AND date_format(report_Time,'%Y%m%d %H:%M:%S') <= date_format(?,'%Y%m%d %H:%M:%S') " + "LIMIT ?" + "    ) a \n" + "GROUP BY DATE_FORMAT( param_time, '%Y-%m-%d %H:%i' ) \n" + "ORDER BY param_time asc ;";
                BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper<>(BDeviceRealDataLineVo.class);
                List<BDeviceRealDataLineVo> queryList = jdbcTemplate.query(sql, rowMapper, bDeviceRealData.getMinute(), bDeviceRealData.getMinute(), bDeviceRealData.getDeviceImei(), paramName, bDeviceRealData.getStartTime(), bDeviceRealData.getEndTime(), bDeviceRealData.getQueryNum());
                for (int j = 0; j < queryList.size(); j++) {
                    if (Convert.toDouble(queryList.get(j).getParamValue()) != null) {
                        doubleList.add(Convert.toDouble(queryList.get(j).getParamValue()));
                    } else {
                        doubleList.add(0.0);
                    }
                    if (i == 0) {
                        timeList.add(queryList.get(j).getParamTime());
                    }
                }
                dataLineVo.setData(doubleList);
                list.add(dataLineVo);
            }
            linesVo.setTimeList(timeList);
            linesVo.setList(list);
        }
        return linesVo;
    }

    @Override
    public void deviceReplyData(String imei, String paramField, String paramValue) {
        if (Detect.notEmpty(paramField) && Detect.notEmpty(paramValue)) {
            String topic = "/IOT/WULIANYUN/SETUP/DATA";
            List<HeartData> data = new ArrayList<>();
            BDeviceHeartData bDeviceHeartData = new BDeviceHeartData();
            bDeviceHeartData.setImei(imei);
            HeartData heartData = new HeartData();
            heartData.setM(paramField);
            heartData.setV(paramValue);
            data.add(heartData);
            bDeviceHeartData.setData(data);
            String message = JSON.toJSONString(bDeviceHeartData);
            // 发送至前端
            PushMessageBo messageBo = new PushMessageBo();
            messageBo.setTopic(topic);
            messageBo.setMessage(message);
            remoteManager.pushCommon(messageBo);
        } else {
            String topic = "/IOT/WULIANYUN/SETUP/DATA";
            List<HeartData> data = new ArrayList<>();
            BDeviceHeartData bDeviceHeartData = new BDeviceHeartData();
            bDeviceHeartData.setImei(imei);
            Collection<String> keys = redisCache.keys("RealData-" + imei + "-*");
            for (String key : keys) {
                Object object = redisCache.getCacheObject(key);
                BDeviceRealData bDeviceRealData = JSON.parseObject(JSON.toJSONString(object), BDeviceRealData.class);
                HeartData heartData = new HeartData();
                heartData.setM(bDeviceRealData.getParamField());
                heartData.setV(Convert.toStr(RandomUtil.randomInt(0, 100)));
                data.add(heartData);
            }
            bDeviceHeartData.setData(data);
            String message = JSON.toJSONString(bDeviceHeartData);
            // 发送至前端
            PushMessageBo messageBo = new PushMessageBo();
            messageBo.setTopic(topic);
            messageBo.setMessage(message);
            remoteManager.pushCommon(messageBo);
        }
    }

    @Override
    public BDeviceRealData getRealData(BDeviceRealData realData) {
        Object cacheObject = redisCache.getCacheObject("RealData-" + realData.getDeviceImei() + "-" + realData.getParamField());
        BDeviceRealData bDeviceRealData = null;
        if (cacheObject != null) {
            bDeviceRealData = JSON.parseObject(JSON.toJSONString(cacheObject), BDeviceRealData.class);
        } else {
            List<BDeviceRealData> bDeviceRealDataList = bDeviceRealDataMapper.selectBDeviceRealDataList(realData);
            if (bDeviceRealDataList.size() > 0) {
                bDeviceRealData = bDeviceRealDataList.get(0);
                redisCache.setCacheObject("RealData-" + bDeviceRealData.getDeviceImei() + "-" + bDeviceRealData.getParamField(), bDeviceRealData);
            }
        }
        return bDeviceRealData;
    }
}
